#include "mocha.h"
#include "espresso_based.h"
#include "ingredient.h"
#include "sub_ingredients.h"
#include <cstddef>
#include <iostream>
#include <ostream>

Mocha::Mocha() 
: EspressoBased() {
    this->name = "Mocha";
    this->ingredients.push_back( new Espresso(2) );
    this->ingredients.push_back(new Milk(2));
    this->ingredients.push_back(new MilkFoam(1));
    this->ingredients.push_back( new Chocolate(1));
}

Mocha::Mocha(const Mocha& cap) {
    this->name        = cap.name;
#define iadd_cond(cond , iname ,unit ) \
if( cond == std::string(#iname))\
    ret = new iname(unit)

    auto iadd = [](std::string iname,size_t unit) {
        Ingredient * ret = nullptr;
        iadd_cond(iname, Cinnamon ,unit);
        iadd_cond(iname, Chocolate,unit);
        iadd_cond(iname, Sugar    ,unit);
        iadd_cond(iname, Cookie   ,unit);
        iadd_cond(iname, Espresso ,unit);
        iadd_cond(iname, Milk     ,unit);
        iadd_cond(iname, MilkFoam ,unit);
        iadd_cond(iname, Water    ,unit);
        return ret;
    };
    for( const auto &i : cap.ingredients )
        this->ingredients.push_back(iadd(i->get_name(),i->get_units()));
    
    for( const auto &i : cap.side_items )
        this->side_items.push_back(iadd(i->get_name(),i->get_units()));

    
}

void Mocha::operator=(const Mocha& cap) {
    if( this != &cap ) {
        this->name = cap.name;
        #define iadd_cond(cond , iname ,unit ) \
        if( cond == std::string(#iname))\
        ret = new iname(unit)

        auto iadd = [](std::string iname,size_t unit) {
            Ingredient * ret = nullptr;
            iadd_cond(iname, Cinnamon ,unit);
            iadd_cond(iname, Chocolate,unit);
            iadd_cond(iname, Sugar    ,unit);
            iadd_cond(iname, Cookie   ,unit);
            iadd_cond(iname, Espresso ,unit);
            iadd_cond(iname, Milk     ,unit);
            iadd_cond(iname, MilkFoam ,unit);
            iadd_cond(iname, Water    ,unit);
            return ret;
        };
        for( const auto &i : this->ingredients )
            delete i;
        this->ingredients.clear();
        for( const auto &i : cap.ingredients )
            this->ingredients.push_back(iadd(i->get_name(),i->get_units()));
        
        for( const auto &i : this->side_items )
            delete i;
        this->side_items.clear();
        for( const auto &i : cap.side_items )
            this->side_items.push_back(iadd(i->get_name(),i->get_units()));
    }
}
std::string Mocha::get_name() {
    return this->name;
}

double Mocha::price() {
    double tprice = 0;
    for( const auto &i : ingredients )
        tprice += i->price();
    
    std::cout << "price checkpoint 1" << std::endl;
    
    for( const auto &i : side_items)
        tprice += i->price();

    std::cout << "price checkpoint 2" << std::endl;
    std::cout << tprice << std::endl;
    return tprice;
}

void Mocha::add_side_item(Ingredient* side) {
    side_items.emplace_back(side);
}

std::vector<Ingredient*>& Mocha::get_side_items() {
    return side_items;
}